package com.chenfan.magic.core;

import com.chenfan.magic.config.DynamicTableHelper;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlParameter;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * 真正执行和处理SQL的类
 *
 * @param
 * @author 周夕
 * @date 2018/8/11 下午10:11
 * @description JdbcTemplate主要提供以下五类方法：
 * execute方法：可以用于执行任何SQL语句，一般用于执行DDL语句；
 * update方法及batchUpdate方法：update方法用于执行新增、修改、删除等语句；batchUpdate方法用于执行批处理相关语句；
 * query方法及queryForXXX方法：用于执行查询相关语句；
 * call方法：用于执行存储过程、函数相关语句。
 * @return
 */
@Slf4j
@Data
public class I extends JdbcTemplate {

    private String script;

    private String index;

    private String resultKey;

    private String templateName;

    private Boolean isPure;

    public void setScript(String script) {
        //换行自动转空格
        script = script.replaceAll("[\\s\\t\\n\\r]", " ");
        this.script = script;
        if (isPure.booleanValue()) {
            log.info("【指标：{} 模板：{}】纯净版~预执行SQL: {}", index, getTemplateDesc(), script);
            this.pureScript();
        } else {
            log.info("【指标：{} 模板：{}】预执行SQL: {}", index, getTemplateDesc(),  script);
        }
    }

    public I() {
        //默认自动从数据源线程池中获取数据源
        this.setQueryTimeout(600000);
    }

    public I(DataSource dataSource) {
        //设置超时时间为10分钟.
        this.setQueryTimeout(600000);
        this.setDataSource(dataSource);
        this.afterPropertiesSet();
    }

    public I(DataSource dataSource, boolean lazyInit) {
        this.setQueryTimeout(600000);
        this.setDataSource(dataSource);
        this.setLazyInit(lazyInit);
        this.afterPropertiesSet();
    }

    /////////////////////////////////  Use  ///////////////////////////


    /**
     * 执行List SQL，返回Map的集合
     *
     * @param sql
     * @param param
     * @return
     */
    public List<Map<String, Object>> queryList(String sql, Object... param) {
        try {
            List<Map<String, Object>> list;
            if (ArrayUtils.isEmpty(param)) {
                list = this.queryForList(sql);
            } else {
                list = this.queryForList(sql, param);
            }
            return list;
        } catch (Exception e) {
            return null;
        }
    }

    public List<Map<String, Object>> queryList() {
        try {
            List<Map<String, Object>> list;
            list = this.queryForList(script);
            return list;
        } catch (Exception e) {
            return null;
        }
    }


    public <T> List<T> queryList(String sql, Class<T> elementType, Object... param) {
        try {
            if (ArrayUtils.isEmpty(param)) {
                return this.queryForList(sql, elementType);
            } else {
                return this.queryForList(sql, elementType, param);
            }
        } catch (Exception e) {
            return null;
        }
    }

    public <T> List<T> queryList(Class<T> elementType, Object... param) {
        try {
            if (ArrayUtils.isEmpty(param)) {
                return this.queryForList(script, elementType);
            } else {
                return this.queryForList(script, elementType, param);
            }
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 执行SQL，返回Map
     *
     * @param sql
     * @param param
     * @return
     */
    public Map<String, Object> queryOne(String sql, Object... param) {
        Map<String, Object> map = Maps.newHashMap();
        try {
            if (ArrayUtils.isEmpty(param)) {
                map = this.queryForMap(sql);
            } else {
                map = this.queryForMap(sql, param);
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }

    public Map<String, Object> queryOne(Object... param) {
        Map<String, Object> map = Maps.newHashMap();
        try {
            if (ArrayUtils.isEmpty(param)) {
                map = this.queryForMap(script);
            } else {
                map = this.queryForMap(script, param);
            }
            return map;
        } catch (Exception e) {
            return null;
        }
    }

    public <T> T queryOne(String sql, Class<T> requiredType) {
        try {
            return this.queryForObject(sql, requiredType);
        } catch (Exception e) {
            return null;
        }
    }

    public <T> T queryOne(Class<T> requiredType) {
        try {
            return this.queryForObject(script, requiredType);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 执行Update SQL，返回受影响的Record行数
     *
     * @param sql
     * @param param
     * @return
     */
    public int updateRecord(String sql, Object... param) {
        if (ArrayUtils.isEmpty(param)) {
            return this.update(sql);
        } else {
            return this.update(sql, param);
        }
    }

    public int updateRecord(Object... param) {
        if (ArrayUtils.isEmpty(param)) {
            return this.update(script);
        } else {
            return this.update(script, param);
        }
    }

    /**
     * 执行批处理语句
     *
     * @return
     */
    public int[] batch(String... sqls) {
        return this.batchUpdate(sqls);
    }

    /**
     * 执行统计SQL，返回得到的整型数字
     *
     * @param sql
     * @return
     */
    public Long count(String sql) {
        try {
            return this.queryForObject(sql, Long.class);
        } catch (Exception e) {
            return -1L;
        }
    }

    public Long count() {
        try {
            return this.queryForObject(script, Long.class);
        } catch (Exception e) {
            return -1L;
        }
    }

    /**
     * 执行DDL, 无回传内容
     */
    public void execute() {
        this.execute(script);
    }

    /**
     * 执行存储过程/函数等, 回传Map
     *
     * @param csc
     * @param declaredParameters
     * @return
     */
    @Override
    public Map<String, Object> call(CallableStatementCreator csc, List<SqlParameter> declaredParameters) {
        return this.call(csc, declaredParameters);
    }

    /**
     * 纯净化脚本
     */
    private void pureScript() {
        Map<String, String> dynamicTableMap = DynamicTableHelper.getDynamicTableMapByIndex(index);
        try {
            if(MapUtils.isEmpty(dynamicTableMap)) {
                log.info("【指标：{} 模板：{}】纯净版暂无或未启用或该指标就是", index, this.getTemplateDesc());
                return;
            }
            String pureScript = this.getScript();
            for(Map.Entry<String, String> entry : dynamicTableMap.entrySet()) {
                pureScript = pureScript.replace(entry.getKey(), entry.getValue());
            }
            this.script = pureScript;
        } catch (Exception e) {
            log.error("【指标：{} 模板：{}】纯净版做表替换异常！", index, this.getTemplateDesc(), e);
        }
    }

    private String getTemplateDesc() {
        if(StringUtils.isBlank(templateName)) {
            return resultKey;
        }
        return templateName;
    }
}